
#include <signal.h>
#include "hw2_common.h"

void handler_sigusr1 (int sig_num);
void handler_sigusr2 (int sig_num);
void parent_handler_sigusr1 (int sig_num);


// number of digits transmitted
int digits = 0;

// number to be printed by child process
unsigned int out_num = 0;


// non-zero means parent should not send signal to child
volatile sig_atomic_t in_handler = 1;      

int main ( int argc, char **argv) {

    unsigned int in_num = 0xfeedbeef; //160;

    printf("%u = %x \n", in_num, in_num);

    pid_t procid = my_fork ();
    
    if (procid != 0)        /* parent process */
    {
        signal (SIGUSR1, parent_handler_sigusr1);

        sigset_t new_mask, old_mask;

        // printf ("parent pid = %d \n", getpid());

        // mask every single bit from low to high
        // and send the bit to child process in this order
        unsigned int mask = 1;

        int i;
        for (i=0; i<32; i++)
        {
            // Block SIGUSR1 AND SIGUSR2 sending from child
            //
            sigemptyset (&new_mask);           
            sigaddset (&new_mask, SIGUSR1);
            sigaddset (&new_mask, SIGUSR2);
            sigprocmask (SIG_SETMASK, &new_mask, &old_mask);                    

            if ( (in_num & (mask << i)) != 0 )
            {
                printf ("send 1 \n");                

                // send 1 to child
                my_kill (procid, SIGUSR2);
            }
            else {
                printf ("send 0 \n");

                // send 0 to child
                my_kill (procid, SIGUSR1);
            }

            // UN-block SIGUSR1, there's still a chance that 
            // SIGUSR arrives before process is suspended
            //
            sigprocmask (SIG_SETMASK, &old_mask, NULL);
            
            // Suspend parent until either SIGUSR1 or SIGUSR2 arrives
            //
            sigset_t parent_block_mask;            
            sigfillset (&parent_block_mask);
            sigdelset (&parent_block_mask, SIGUSR1);
            sigdelset (&parent_block_mask, SIGUSR2);
            
            //sigset_t pending_sig;
            //sigpending (&pending_sig);

            //if (sigismember (&pending_sig, SIGUSR1) == 0)
                sigsuspend (&parent_block_mask); 
            
        }

        int exit_status;

        // block until child process terminates
        my_waitpid (procid, &exit_status, 0);

        // non-zero if child terminated normally
        if ( WIFEXITED (exit_status) != 0 ) {
            printf ("now parent exits \n");
            // do nothing
        }
    }
    else                     /* child process */
    {
        // printf ("child pid = %d \n", getpid());

       // struct sigaction act_sigusr1;
       // struct sigaction act_sigusr2;

       // sigset_t block_mask;

       // /* Block SIGUSR2 while SIGUSR1 handler runs
       //  * and vice versa */

       // sigemptyset (&block_mask);
       // sigaddset (&block_mask, SIGUSR1);
       // sigaddset (&block_mask, SIGUSR2);
       // //sigaddset (&block_mask, SIGUSR1 | SIGUSR2);

       // act_sigusr1.sa_handler = handler_sigusr1;
       // act_sigusr1.sa_mask = block_mask;
       // act_sigusr1.sa_flags = 0;

       // act_sigusr2.sa_handler = handler_sigusr2;
       // act_sigusr2.sa_mask = block_mask;
       // act_sigusr2.sa_flags = 0;

       // sigaction (SIGUSR1, &act_sigusr1, NULL);
       // sigaction (SIGUSR2, &act_sigusr2, NULL);


        // SIGUSR1 = 0, SIGUSR2 = 1    
        signal (SIGUSR1, handler_sigusr1);
        signal (SIGUSR2, handler_sigusr2);
                        
        while (digits<32)
        {                        
            /* suspend this child until a SIGUSR1 or SIGUSR2 arrives */
            sigset_t block_mask;            
            sigfillset (&block_mask);
            sigdelset (&block_mask, SIGUSR1);
            sigdelset (&block_mask, SIGUSR2);
            // sigdelset (&block_mask, SIGUSR1 | SIGUSR2);
            
            sigsuspend (&block_mask);             
        }

        printf ("number received by child = %x \n", out_num);
    }    

    return 0;
}


// Child's Handler for SIGUSR1 signal ( or 0 )
//
void handler_sigusr1(int sig_num)
{   
    //printf ("in SIGUSR1 handler \n");

    // only increment digits
    digits++;

    my_kill (getppid(), SIGUSR1);

    //printf("signal sent to parent \n");
}


// Child's handler for SIGUSR2 signal ( or 1 )
//
void handler_sigusr2(int sig_num)
{
    //printf ("in SIGUSR2 handler \n");

    digits++;

    out_num = out_num | (1 << (digits-1));    

    my_kill (getppid(), SIGUSR1);

    //printf("signal sent to parent \n");
}


// Parent's SIGUSR1 handler
//
void parent_handler_sigusr1 (int sig_num)
{
    // do nothing
}
